package com.sample.datastore

import android.content.Context
import androidx.datastore.core.DataStore
import androidx.datastore.preferences.core.*
import androidx.datastore.preferences.preferencesDataStore
import com.sample.App
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking

/**
 * time 2019/12/5
 * author wxl
 * sp调用对象
 */
object Sp {

    const val STORE_NAME = "demo_data_store"
    const val COMMON_STORE_NAME = "common_data_store"

    val Context.dataStore by preferencesDataStore(STORE_NAME)

    val Context.commonDataStore by preferencesDataStore(COMMON_STORE_NAME)

//    private fun <T> put(key: String, value: T) = with(preferences.edit()) {
//        when (value) {
//            is String? -> putString(key, value)
//            is Int -> putInt(key, value)
//            is Long -> putLong(key, value)
//            is Float -> putFloat(key, value)
//            is Boolean -> putBoolean(key, value)
//            else -> throw IllegalArgumentException("This type can be saved into Preferences.")
//        }.apply()
//    }

    private fun put(key: String, value: Any?) = runBlocking { putX(key, value) }

    private fun put2(key: String, value: Any?) =
        runBlocking { putX(App.instance.dataStore, key, value) }

    private suspend fun putX(key: String, value: Any?) =
        putX(App.instance.commonDataStore, key, value)

    fun put(dataStore: DataStore<Preferences>, key: String, value: Any?) =
        runBlocking { putX(dataStore, key, value) }

    suspend fun putX(dataStore: DataStore<Preferences>, key: String, value: Any?) =
        with(dataStore) {
            if (value == null) {
                edit { it.remove(stringPreferencesKey(key)) }
            } else {
                when (value) {
                    is String -> edit { it[stringPreferencesKey(key)] = value }
                    is Int -> edit { it[intPreferencesKey(key)] = value }
                    is Long -> edit { it[longPreferencesKey(key)] = value }
                    is Float -> edit { it[floatPreferencesKey(key)] = value }
                    is Double -> edit { it[doublePreferencesKey(key)] = value }
                    is Boolean -> edit { it[booleanPreferencesKey(key)] = value }
                    else -> edit {
//                        it[stringPreferencesKey(key)] = value.objectToJson() ?: ""
                    }
                }
            }
        }

//    @Suppress("UNCHECKED_CAST")
//    private inline fun <reified T> get(name: String, defaultValue: T): T = with(preferences) {
//        val res = when (T::class) {
//            String::class -> getString(name, defaultValue as String?)
//            Int::class -> getInt(name, defaultValue as Int)
//            Long::class -> getLong(name, defaultValue as Long)
//            Float::class -> getFloat(name, defaultValue as Float)
//            Boolean::class -> getBoolean(name, defaultValue as Boolean)
//            else -> throw IllegalArgumentException("This type can be saved into Preferences.")
//        }
//        return res as T
//    }

    private inline fun <reified T> get(key: String, defaultValue: T? = null): T? =
        runBlocking { getX(key, defaultValue) }

    private inline fun <reified T> get2(key: String, defaultValue: T? = null): T? =
        runBlocking { getX(App.instance.dataStore, key, defaultValue) }

    private suspend inline fun <reified T> getX(key: String, defaultValue: T? = null): T? =
        getX(App.instance.commonDataStore, key, defaultValue)

    inline fun <reified T> get(
        dataStore: DataStore<Preferences>, key: String, defaultValue: T? = null
    ): T? = runBlocking { getX(dataStore, key, defaultValue) }

    suspend inline fun <reified T> getX(
        dataStore: DataStore<Preferences>, key: String, defaultValue: T? = null
    ): T? = with(dataStore.data) {
        val res = when (T::class) {
            String::class -> map { it[stringPreferencesKey(key)] }
            Int::class -> map { it[intPreferencesKey(key)] }
            Long::class -> map { it[longPreferencesKey(key)] }
            Float::class -> map { it[floatPreferencesKey(key)] }
            Double::class -> map { it[doublePreferencesKey(key)] }
            Boolean::class -> map { it[booleanPreferencesKey(key)] }
            else -> map {
//                it[stringPreferencesKey(key)].jsonToObject<T>()
            }
        }
        return (res.first() as? T?) ?: defaultValue
    }

    private val mCommon by lazy { Common() }

    /**
     * 获取公共变量
     */

    fun getCommon() = mCommon


    /**
     * 公共的变量
     */
    class Common {

        companion object {
            private const val SERVICE_IP = "service_ip"
            private const val SERVICE_PORT = "service_port"
            private const val FTP_IP = "ftp_ip"
            private const val FTP_PORT = "ftp_port"
            private const val FTP_HTTP_PORT = "ftp_http_port"
            private const val FTP_USER = "ftp_user"
            private const val FTP_PWD = "ftp_pwd"
            private const val FTP_BASE_PATH = "ftp_base_path"
            private const val TERMINAL_CODE = "terminal_code"
            private const val EMP_ID = "emp_id"
        }


        /**
         * 设置登录人员Id
         */
        fun setEmpId(empId: Long) = put(EMP_ID, empId)

        fun getEmpId() = get(EMP_ID, 0L)!!

        /**
         * 设置服务器ip
         */
        fun setServiceIp(ip: String) = put2(SERVICE_IP, ip)

        fun getServiceIp() = get2(SERVICE_IP, "192.168.1.1")!!

        /**
         * 设置服务器port
         */
        fun setServicePort(port: String) = put2(SERVICE_PORT, port)

        fun getServicePort() = get2(SERVICE_PORT, "8003")!!

        /**
         * 设置终端编码
         */
        fun setTerminalCode(terminalCode: String) = put(TERMINAL_CODE, terminalCode)

        fun getTerminalCode() = get(TERMINAL_CODE, "patrol_1000")!!


        /**
         * 设置Ftp服务器地址
         */
        fun setFtpIp(ftpIp: String?) = put(FTP_IP, ftpIp)

        fun getFtpIp() = get(FTP_IP, "192.168.1.1")!!

        /**
         * 设置Ftp端口
         */
        fun setFtpPort(ftpPort: String?) {
            put(FTP_PORT, ftpPort)
        }

        fun getFtpPort() = get(FTP_PORT, "21")!!

        /**
         * 设置FtpHttp端口
         */
        fun setFtpHttpPort(ftpPort: String?) = put(FTP_HTTP_PORT, ftpPort)

        fun getFtpHttpPort() = get(FTP_HTTP_PORT, "8005")!!

        /**
         * 设置Ftp用户
         */
        fun setFtpUser(ftpUser: String?) = put(FTP_USER, ftpUser)

        fun getFtpUser() = get(FTP_USER, "")!!

        /**
         * 设置Ftp用户密码
         */
        fun setFtpPwd(ftpPwd: String?) = put(FTP_PWD, ftpPwd)

        fun getFtpPwd() = get(FTP_PWD, "")!!

        /**
         * 设置Ftp 根路径
         */
        fun setFtpBasePath(ftpBasePath: String?) = put(FTP_BASE_PATH, ftpBasePath)

        fun getFtpBasePath() = get(FTP_BASE_PATH, "")!!

    }


}